<template>
  <div class="topo-main">
    <vue-ruler-tool
      :parent="true"
      :is-scale-revise="true"
      style="width:100%;height: calc(100% - 35px);"
    >
      <div
        id="surface-edit-layer"
        tabindex="0"
        class="topo-layer"
        :class="{'topo-layer-view-selected': selectedIsLayer}"
        :style="layerStyle"
        @click="onLayerClick($event)"
        @mouseup="onLayerMouseup($event)"
        @mousemove="onLayerMousemove($event)"
        @mousedown="onLayerMousedown($event)"
        @keyup.delete="removeItem()"
        @dragover.prevent
        @drop="onDrop"
        @keydown.ctrl.67.stop="copyItem"
        @keydown.ctrl.86.stop="pasteItem"
        @keydown.ctrl.90.stop="undo"
        @keydown.ctrl.89.stop="redo"
      >
        <template v-for="(component,index) in configData.components">
          <div
            :key="component.identifier"
            tabindex="0"
            class="topo-layer-view"
            :class="{'topo-layer-view-selected': selectedComponentMap[component.identifier] === undefined ? false:true }"
            :style="component  | parseComponentStyle"
            @click.stop="clickComponent(index,component,$event)"
            @mousedown.stop="controlMousedown(component,$event,index)"
            @keyup.delete="removeItem()"
            @keydown.up.exact.prevent="moveItems('up')"
            @keydown.right.exact.prevent="moveItems('right')"
            @keydown.down.exact.prevent="moveItems('down')"
            @keydown.left.exact.prevent="moveItems('left')"
            @keydown.ctrl.67.stop="copyItem"
            @keydown.ctrl.86.stop="pasteItem"
            @keydown.ctrl.90.stop="undo"
            @keydown.ctrl.89.stop="redo"
          >
            <component
              :is="parseView(component)"
              v-show="component.style.visible"
              :ref="'comp' + index"
              :detail="component"
              :edit-mode="true"
              :selected="selectedComponentMap[component.identifier] ? true : false"
            />

            <div
              v-if="component.dataBind && component.dataBind.name"
              style="position: absolute;height: 30px;left: 40%;top: 40%;background-color: white;border: 1px dotted #0cf;line-height: 30px;opacity: 0.5;"
            >{{
              component.dataBind.name
            }}
            </div>
            <div
              v-if="component.dataBind && component.dataBind.showTypeList"
              style="position: absolute;height: 30px;left: 0px;top: -30px;"
            >
              <el-select
                v-model="component.dataBind.showType"
                style="width: 100px"
              >
                <el-option
                  v-for="(showType,showTypeIndex) in component.dataBind.showTypeList"
                  :key="showTypeIndex"
                  :label="showType.label"
                  :value="showType.value"
                />
              </el-select>
            </div>
            <div
              v-show="selectedComponentMap[component.identifier]"
              class="resize-left-top"
              @mousedown.stop="resizeMousedown(component,$event,index,'resize-lt')"
            />
            <div
              v-show="selectedComponentMap[component.identifier]"
              class="resize-left-center"
              @mousedown.stop="resizeMousedown(component,$event,index,'resize-lc')"
            />
            <div
              v-show="selectedComponentMap[component.identifier]"
              class="resize-left-bottom"
              @mousedown.stop="resizeMousedown(component,$event,index,'resize-lb')"
            />
            <div
              v-show="selectedComponentMap[component.identifier]"
              class="resize-right-top"
              @mousedown.stop="resizeMousedown(component,$event,index,'resize-rt')"
            />
            <div
              v-show="selectedComponentMap[component.identifier]"
              class="resize-right-center"
              @mousedown.stop="resizeMousedown(component,$event,index,'resize-rc')"
            />
            <div
              v-show="selectedComponentMap[component.identifier]"
              class="resize-right-bottom"
              @mousedown.stop="resizeMousedown(component,$event,index,'resize-rb')"
            />
            <div
              v-show="selectedComponentMap[component.identifier]"
              class="resize-center-top"
              @mousedown.stop="resizeMousedown(component,$event,index,'resize-ct')"
            />
            <div
              v-show="selectedComponentMap[component.identifier]"
              class="resize-center-bottom"
              @mousedown.stop="resizeMousedown(component,$event,index,'resize-cb')"
            />
          </div>
        </template>
        <div
          class="topo-frame-selection"
          :style="{width: frameSelectionDiv.width + 'px',height: frameSelectionDiv.height + 'px',top: frameSelectionDiv.top + 'px',left: frameSelectionDiv.left + 'px'}"
        />
      </div>
    </vue-ruler-tool>
    <el-form
      style="margin-top: 5px"
      inline
    >
      <el-form-item>
        {{ $t('choose') }}:{{ selectedComponents.length }}
      </el-form-item>
      <el-form-item>
        <el-button
          type="primary"
          @click="updateTemplate"
        >{{ $t('update') }}
        </el-button>
      </el-form-item>
      <el-form-item>
        <el-button
          type="primary"
          @click="fullScreen"
        >{{ $t('preview') }}
        </el-button>
      </el-form-item>
      <el-form-item :label="$t('zoom')">
        <el-slider
          v-model="selectedValue"
          :min="30"
          :max="200"
          style="width:200px;"
        />
      </el-form-item>
    </el-form>
  </div>
</template>

<script>
import VueRulerTool from './VueRulerTool'
import TopoBase from './TopoBase'
import { parseComponentStyle, parseLayerStyle, parseViewName } from './util/topoUtil'
import { deepCopy } from '@/topo/assets/libs/utils'
import { checkByRectCollisionDetection } from '@/topo/assets/libs/topo'
import { mapActions, mapMutations, mapState } from 'vuex'
import { successNotice } from '@/util/common'
import { getDeviceViewTemplate, updateDeviceViewTemplate } from '@/api/iot/iotDeviceViewTemplateApi'

export default {
  name: 'TopoMain',
  components: {
    VueRulerTool
  },
  filters: {
    parseComponentStyle(item) {
      return parseComponentStyle(item)
    }
  },
  extends: TopoBase,
  props: [],
  computed: {
    ...mapState({
      selectedComponents: state => state.topoEditor.selectedComponents,
      selectedComponentMap: state => state.topoEditor.selectedComponentMap,
      configData: state => state.topoEditor.topoData,
      selectedIsLayer: state => state.topoEditor.selectedIsLayer,
      copySrcItems: state => state.topoEditor.copySrcItems,
      copyCount: state => state.topoEditor.copyCount
    }),
    layerStyle() {
      const styles = parseLayerStyle(this.configData.layer)
      const scale = this.selectedValue / 100
      styles.push(`transform:scale(${scale})`)
      return styles.join(';')
    }

  },
  data() {
    return {
      moveItem: {
        startX: 0,
        startY: 0
      }, // 移动组件 相关变量
      resizeItem: {
        startPx: 0,
        startPy: 0,
        x: 0,
        y: 0,
        w: 0,
        h: 0
      }, // resize组件 相关变量
      frameSelectionDiv: {
        width: 0,
        height: 0,
        top: 10,
        left: 10,
        startX: 0,
        startY: 0,
        startPageX: 0,
        startPageY: 0
      },
      flag: '', // 当前操作标志位
      curControl: null,
      curIndex: -1,
      selectedValue: 100,
      templateId: null,
      deviceId: null
    }
  },
  created() {
    const param = this.$route.query
    this.templateId = param.templateId
    this.templateName = param.templateName
    this.deviceId = param.deviceId
    this.getDeviceViewTemplate()
  },
  methods: {

    getDeviceViewTemplate() {
      getDeviceViewTemplate({
        templateId: this.templateId
      }).then(res => {
        const { code, data } = res
        if (code === '200') {
          const jsonConfig = JSON.parse(data.jsonConfig)
          this.setTopoData(jsonConfig)
        }
      })
    },
    updateTemplate() {
      const configData = JSON.parse(JSON.stringify(this.configData))
      configData.components.forEach(component => {
        component.dataBind.editModel = false
      })
      const jsonConfig = JSON.stringify(configData)
      updateDeviceViewTemplate({
        jsonConfig: jsonConfig,
        templateId: this.templateId
      }).then(res => {
        const { code } = res
        if (code === '200') {
          successNotice(this)
        }
      })
    },
    ...mapMutations('topoEditor', [
      'setSelectedComponent',
      'addSelectedComponent',
      'removeSelectedComponent',
      'clearSelectedComponent',
      'setLayerSelected',
      'setCopySrcItems',
      'increaseCopyCount',
      'execute',
      'undo',
      'redo'
    ]),
    ...mapActions('topoEditor', [
      'loadDefaultTopoData',
      'setTopoData'
    ]),
    controlMousedown(component, event, index) {
      if (event.ctrlKey) {
        return
      }
      this.flag = 'move'
      this.curControl = component
      this.clickItem(component, index)
      this.moveItem.startX = event.pageX
      this.moveItem.startY = event.pageY
      // 记录初始信息--move
      for (const key in this.selectedComponentMap) {
        const component = this.selectedComponentMap[key]
        component.style.temp = {}
        component.style.temp.position = {}
        component.style.temp.position.x = component.style.position.x
        component.style.temp.position.y = component.style.position.y
      }
    },
    resizeMousedown(component, $event, index, flag) { // resize-鼠标按下事件
      this.flag = flag
      this.curControl = component
      this.curIndex = index
      this.clickItem(component, index)
      this.resizeItem.startPx = event.pageX
      this.resizeItem.startPy = event.pageY
      // 记录初始信息-resize
      this.resizeItem.x = this.curControl.style.position.x
      this.resizeItem.y = this.curControl.style.position.y
      this.resizeItem.w = this.curControl.style.position.w
      this.resizeItem.h = this.curControl.style.position.h
    },
    onLayerMousemove(event) {
      if (event.which !== 1) {
        this.flag = ''
        return
      }
      if (this.flag === '') {
        return
      }
      if (this.flag.startsWith('resize')) {
        let dx = event.pageX - this.resizeItem.startPx
        let dy = event.pageY - this.resizeItem.startPy
        switch (this.flag) {
          case 'resize-lt':
            this.curControl.style.position.x = this.resizeItem.x + dx
            this.curControl.style.position.y = this.resizeItem.y + dy
            dx = -dx
            dy = -dy
            break
          case 'resize-lc':
            this.curControl.style.position.x = this.resizeItem.x + dx
            dy = 0
            dx = -dx
            break
          case 'resize-lb':
            this.curControl.style.position.x = this.resizeItem.x + dx
            dx = -dx
            break
          case 'resize-rt':
            this.curControl.style.position.y = this.resizeItem.y + dy
            dy = -dy
            break
          case 'resize-rc':
            dy = 0
            break
          case 'resize-rb':
            break
          case 'resize-ct':
            this.curControl.style.position.y = this.resizeItem.y + dy
            dx = 0
            dy = -dy
            break
          case 'resize-cb':
            dx = 0
            break
        }
        if ((this.resizeItem.w + dx) > 20) {
          this.curControl.style.position.w = this.resizeItem.w + dx
        }
        if ((this.resizeItem.h + dy) > 20) {
          this.curControl.style.position.h = this.resizeItem.h + dy
        }
        // canvas组件需要重新渲染
        // DOM 还没有更新
        this.$nextTick(function() {
          // DOM 更新了
          const a = this.$refs['comp' + this.curIndex][0]
          a.onResize()
        })
      } else if (this.flag === 'move') {
        // 移动组件
        const dx = event.pageX - this.moveItem.startX
        const dy = event.pageY - this.moveItem.startY
        for (const key in this.selectedComponentMap) {
          const component = this.selectedComponentMap[key]
          component.style.position.x = component.style.temp.position.x + dx
          component.style.position.y = component.style.temp.position.y + dy
        }
      } else if (this.flag === 'frame_selection') {
        this.onFrameSelection(event)
      }
    },
    onLayerMouseup(event) {
      if (this.flag.startsWith('resize')) {
        const a = this.$refs['comp' + this.curIndex][0]
        a.onResize()
      } else if (this.flag === 'frame_selection') {
        // 由于和onLayerClick冲突，这里模拟下点击空白区域
        this.onFrameSelection(event)
        this.frameSelectionDiv.width = 0
        this.frameSelectionDiv.height = 0
        this.frameSelectionDiv.top = 0
        this.frameSelectionDiv.left = 0
      } else if (this.flag === 'move') {
        // 鼠标move只是方便用户预览，真正执行应该用命令，所以要先恢复
        const dx = event.pageX - this.moveItem.startX
        const dy = event.pageY - this.moveItem.startY
        for (const key in this.selectedComponentMap) {
          const component = this.selectedComponentMap[key]
          component.style.position.x = component.style.position.x - dx
          component.style.position.y = component.style.position.y - dy
        }
        this.execute({
          op: 'move',
          dx: dx,
          dy: dy,
          items: this.selectedComponentMap
        })
      }
      this.flag = ''
    },
    onLayerMousedown($event) {
      this.flag = 'frame_selection'
      this.frameSelectionDiv.startX = $event.offsetX
      this.frameSelectionDiv.startY = $event.offsetY
      this.frameSelectionDiv.startPageX = $event.pageX
      this.frameSelectionDiv.startPageY = $event.pageY
    },
    onLayerClick() {
      // this.clearSelectedComponent();
      // this.setLayerSelected(true);
    },
    onFrameSelection(event) {
      const dx = event.pageX - this.frameSelectionDiv.startPageX
      const dy = event.pageY - this.frameSelectionDiv.startPageY
      this.frameSelectionDiv.width = Math.abs(dx)
      this.frameSelectionDiv.height = Math.abs(dy)
      if (dx > 0 && dy > 0) {
        this.frameSelectionDiv.top = this.frameSelectionDiv.startY
        this.frameSelectionDiv.left = this.frameSelectionDiv.startX
      } else if (dx > 0 && dy < 0) {
        this.frameSelectionDiv.top = this.frameSelectionDiv.startY + dy
        this.frameSelectionDiv.left = this.frameSelectionDiv.startX
      } else if (dx < 0 && dy > 0) {
        this.frameSelectionDiv.top = this.frameSelectionDiv.startY
        this.frameSelectionDiv.left = this.frameSelectionDiv.startX + dx
      } else if (dx < 0 && dy < 0) {
        this.frameSelectionDiv.top = this.frameSelectionDiv.startY + dy
        this.frameSelectionDiv.left = this.frameSelectionDiv.startX + dx
      }
      // 判断各个组件是否在方框内
      const rect = {
        x: this.frameSelectionDiv.left,
        y: this.frameSelectionDiv.top,
        width: this.frameSelectionDiv.width,
        height: this.frameSelectionDiv.height
      }
      const components = this.configData.components
      components.forEach(component => {
        const itemRect = {
          x: component.style.position.x,
          y: component.style.position.y,
          width: component.style.position.w,
          height: component.style.position.h
        }
        if (checkByRectCollisionDetection(rect, itemRect)) {
          this.addSelectedComponent(component)
        } else {
          this.removeSelectedComponent(component)
        }
      })
      if (this.selectedComponents.length > 0) {
        this.setLayerSelected(false)
      } else {
        this.setLayerSelected(true)
      }
    },
    onDrop(event) {
      event.preventDefault()
      const infoJson = event.dataTransfer.getData('my-topo-info')
      const component = JSON.parse(infoJson)
      if (this.checkAddComponent(component) === false) {
        return
      }
      // 判断当前着陆点是不是layer
      if (event.target.id === 'surface-edit-layer') {
        component.style.position.x = event.offsetX
        component.style.position.y = event.offsetY
      } else {
        // 解决着陆灯不是layer的情形
        const layer = event.currentTarget
        const position = layer.getBoundingClientRect()
        const x = event.clientX - position.left
        const y = event.clientY - position.top
        component.style.position.x = x
        component.style.position.y = y
      }
      // 处理默认值
      this.execute({
        op: 'add',
        component: component
      })
      // 默认选中，并点击
      this.clickItem(component, this.configData.components.length - 1)
    },
    moveItems(direction) {
      let dx = 0
      let dy = 0
      if (direction === 'up') {
        dy = -5
      } else if (direction === 'right') {
        dx = 5
      } else if (direction === 'down') {
        dy = 5
      } else if (direction === 'left') {
        dx = -5
      }
      this.execute({
        op: 'move',
        dx: dx,
        dy: dy,
        items: this.selectedComponentMap
      })
    },
    checkAddComponent(info) {
      if (info == null) {
        this.$q.notify({
          type: 'negative',
          position: 'bottom-right',
          message: 'This component not surpport.'
        })
        return false
      }
      return true
    },
    parseView(component) {
      return parseViewName(this.deviceId, component)
    },
    clickItem(component, index) {
      this.setLayerSelected(false)
      if (this.selectedComponentMap[component.identifier] === undefined) {
        this.setSelectedComponent(component)
      } else {
        // 如果已经选中，则不做任何处理
      }
    },
    clickComponent(index, component, event) { // 点击组件
      if (event.ctrlKey === true) { // 点击了ctrl
        this.setLayerSelected(false)
        if (this.selectedComponentMap[component.identifier] === undefined) {
          this.addSelectedComponent(component)
        } else {
          this.removeSelectedComponent(component)
        }
      } else {
        // 这里不再处理点击事件，改为鼠标左键
        // this.clickItem(component,index);
      }
    },
    copyItem() { // 设定复制源
      const items = []
      for (const key in this.selectedComponentMap) {
        const item = deepCopy(this.selectedComponentMap[key])
        items.push(item)
      }
      this.setCopySrcItems(items)
    },
    pasteItem() {
      if (this.copySrcItems && this.copySrcItems.length > 0) {
        this.execute({
          op: 'copy-add',
          items: this.copySrcItems
        })
      }
    },
    removeItem(index, component) { // 移除组件
      this.execute({
        op: 'del',
        index: index
      })
      this.setLayerSelected(true)
    },
    fullScreen() {
      localStorage.setItem('topoData', JSON.stringify(this.configData))
      window.open('#/topo/fullscreen' + '?deviceId=' + this.deviceId)
      // this.$router.push({
      //   path: '/topo/fullscreen',
      //   name: 'TopoFullscreen',
      //   query: { deviceId: this.deviceId }
      // })
    }
  }
}
</script>

<style scoped lang="scss">
.topo-main {
  //position: relative;
  overflow-x: hidden;
  overflow-y: hidden;

  .topo-layer {
    width: 100%;
    height: 100%;
    position: relative;
    //transform-origin: left top;
    //overflow: auto;
    // background-color: white;
    // background-clip: padding-box;
    // background-origin: padding-box;
    // background-repeat: no-repeat;
    // background-size: 100% 100%;

    //background-image: linear-gradient(45deg, #ccc 25%, transparent 25%, transparent 75%, #ccc 75%, #ccc),
    //linear-gradient(45deg, #ccc 25%, transparent 25%, transparent 75%, #ccc 75%, #ccc);
    //background-size: 20px 20px;
    //background-position: 0 0, 10px 10px;

    .topo-frame-selection {
      background-color: #8787e7;
      opacity: 0.3;
      border: #0000ff solid 1px;
      position: absolute;
      z-index: 999;
    }

    .topo-layer-view {
      position: absolute;
      height: 100px;
      width: 100px;
      background-color: #999;
      cursor: move;
      border: #ccc solid 1px;

      .resize-left-top {
        position: absolute;
        height: 10px;
        width: 10px;
        background-color: white;
        border: 1px solid #0cf;
        left: -5px;
        top: -5px;
        cursor: nwse-resize;
      }

      .resize-left-center {
        position: absolute;
        height: 10px;
        width: 10px;
        background-color: white;
        border: 1px solid #0cf;
        left: -5px;
        top: 50%;
        margin-top: -5px;
        cursor: ew-resize;
      }

      .resize-left-bottom {
        position: absolute;
        height: 10px;
        width: 10px;
        background-color: white;
        border: 1px solid #0cf;
        left: -5px;
        bottom: -5px;
        cursor: nesw-resize;
      }

      .resize-right-top {
        position: absolute;
        height: 10px;
        width: 10px;
        background-color: white;
        border: 1px solid #0cf;
        right: -5px;
        top: -5px;
        cursor: nesw-resize;
      }

      .resize-right-center {
        position: absolute;
        height: 10px;
        width: 10px;
        background-color: white;
        border: 1px solid #0cf;
        right: -5px;
        top: 50%;
        margin-top: -5px;
        cursor: ew-resize;
      }

      .resize-right-bottom {
        position: absolute;
        height: 10px;
        width: 10px;
        background-color: white;
        border: 1px solid #0cf;
        right: -5px;
        bottom: -5px;
        cursor: nwse-resize;
      }

      .resize-center-top {
        position: absolute;
        height: 10px;
        width: 10px;
        background-color: white;
        border: 1px solid #0cf;
        top: -5px;
        left: 50%;
        margin-left: -5px;
        cursor: ns-resize;
      }

      .resize-center-bottom {
        position: absolute;
        height: 10px;
        width: 10px;
        background-color: white;
        border: 1px solid #0cf;
        bottom: -5px;
        left: 50%;
        margin-left: -5px;
        cursor: ns-resize;
      }
    }

    .topo-layer-view-selected {
      outline: 1px solid #0cf;
    }
  }
}
</style>
